<html>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<head>
<title>Section 13.3.&nbsp; Sessions</title>
<link rel="STYLESHEET" type="text/css" href="images/style.css">
<link rel="STYLESHEET" type="text/css" href="images/docsafari.css">
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-13-SECT-2.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-13-SECT-4.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
<br><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><TD valign="top"><a name="learnphpmysql-CHP-13-SECT-3"></a>
<h3 id="631450-969" class="docSection1Title">13.3. Sessions</h3>
<a name="IDX-CHP-13-0617"></a> 

<p class="docText">HTML and web servers by default don't keep track of information that was entered on a page when the client's browser loads another page. This makes doing anything that involves using the same information from a user on several pages difficult.</p>
<p class="docText">Sessions help solve this problem by maintaining data during a user's visit to your web site from page to page on your site. Each session can store many variables that are maintained throughout that session. The server keeps track of users' sessions by assigning them a unique session ID, generated by the server, when the session starts. This identifier is called the <span class="docEmphasis">session identifier</span> and must be sent to the server each time a page is requested once a session begins. <a class="docLink" href="#learnphpmysql-CHP-13-FIG-7">Figure 13-7</a> illustrates the interaction between the client browser and web server for a session.</p>
<a name="learnphpmysql-CHP-13-FIG-7"></a><p><center>
<h5 class="docFigureTitle">Figure 13-7. A typical session stores some information on both the client and server hard disks</h5>
<img border="0" alt="" id="195131084204" width="549" height="224" SRC="images/learnphpmysql_1307.jpg">
</center></p><br>
<p class="docText">Sessions are stored on the server. The session variables are stored in a file and are <span class="docEmphasis">serialized</span>. When a variable is serialized, it's written out to a file as its name, type, and value all in a sequential string. On a Unix-based server, this file is usually written out to a directory under the <span class="docEmphasis">/tmp</span> (temporary) filesystem.</p>
<p><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><tr><TD><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><tr><td width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></TD><TD valign="top">
<p class="docText">PHP doesn't actually create a record for a session until a session variable has been assigned a value. That makes sense since without any values to manage, the session doesn't really do anything.</p>
</TD></tr></table></td></tr></table></P><br>
<p class="docText">The browser sends the session ID to the server each time it requests a page. The browser can send the session ID to the server either through a cookie or as a URL parameter. The default is to use the cookie, but because it's possible for a user to turn off cookies in his browser preferences, we also discuss passing the session ID in the URL string.</P>
<a name="learnphpmysql-CHP-13-SECT-3.1"></a>
<h4 id="title-IDAQGCWC" class="docSection2Title">13.3.1. Using Sessions</h4>
<a name="IDX-CHP-13-0618"></a> 
<a name="IDX-CHP-13-0619"></a> 
<a name="IDX-CHP-13-0620"></a> 
<a name="IDX-CHP-13-0621"></a> 

<p class="docText">To start a session, place the <tt>session_start</tt><a name="IDX-CHP-13-0622"></a> 
 function at the beginning of your PHP script before you can store or access any data during in the session. The <tt>session_start</tt> function, used in <a class="docLink" href="#learnphpmysql-CHP-13-EX-10">Example 13-10</a>, needs to execute before any other <tt>header</tt> calls or other output is sent to the browser; otherwise, your session may not work properly.</P>
<a name="learnphpmysql-CHP-13-EX-10"></a><H5 id="title-IDAZHCWC" class="docExampleTitle">Example 13-10. Simply starting a session</h5><P><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;?php
    session_start();
?&gt;
</pre><BR>

</TD></tr></table></p>
<p class="docText">First, we'll discuss the way variables used to be assigned to a session, since you may see this in code you get off the Web. The old school way is to use the <tt>session_register</tt> function, shown in <a class="docLink" href="#learnphpmysql-CHP-13-EX-11">Example 13-11</a>. Don't use this method in your code, as it will cause an error.</p>
<a name="learnphpmysql-CHP-13-EX-11"></a><h5 id="title-IDAPICWC" class="docExampleTitle">Example 13-11. Registering a variable with session_register</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
&lt;?php
//DON'T USE THIS APPROACH
session_start();
session_register("hello");
$hello = "Hello World";
?&gt;
</pre><br>

</TD></TR></table></p>
<p class="docText">Once the variable is bound like this in a PHP script, any changes to the variable are stored in the session. If the session isn't already started, the <tt>session_register</tt> command automatically starts it. Modern PHP interpreters return a warning with this code:</P>
<pre>
Warning: Unknown(): Your script possibly relies on a session side-effect which
existed until PHP 4.2.3. Please be advised that the session extension does not
consider global variables as a source of data, unless register_globals is enabled.
You can disable this functionality and this warning by setting
session.bug_compat_42 or session.bug_compat_warn to off, respectively. in Unknown
on line 0
</pre><br>

<p class="docText">The correct way is to store and access session variables by the <tt>$_SESSION</tt> global variable with the name of the variable supplied within brackets. Assigning a new variable to the <tt>$_SESSION</tt> global automatically adds it to the session. The session must be started before you can access the session variables.</p>
<p><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><tr><td><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><tr><td width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></td><td valign="top">
<p class="docText">The use of <tt>session_register</tt> is considered to be less secure than using <tt>$_SESSION</tt> because of the possibility of a malicious user sending a value as a <tt>GET</tt> parameter with the same name as a registered session variable. For example, an attacker could send a bogus value for <tt>$username</tt> and make your PHP script believe a user is logged in who really didn't pass authentication.</p>
</td></tr></table></TD></tr></table></p><BR>
<p class="docText">For instance, <a class="docLink" href="#learnphpmysql-CHP-13-EX-12">Example 13-12</a> registers the same variable.</P>
<a name="learnphpmysql-CHP-13-EX-12"></a><h5 id="title-IDA4JCWC" class="docExampleTitle">Example 13-12. Registering a variable by including it in $_SESSION</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;?php
    session_start();
    $_SESSION['hello'] = 'Hello World';
    echo $_SESSION['hello'];
?&gt;
</pre><BR>

</td></TR></table></p>
<p class="docText">Now if the user was to follow a link to another page on your site that starts a session, the <tt>$_SESSION</tt> global variable contains a key called <tt>hello</tt> with the string value of <tt>Hello World</tt>, as shown in <a class="docLink" href="#learnphpmysql-CHP-13-EX-13">Example 13-13</a>.</p>
<a name="learnphpmysql-CHP-13-EX-13"></a><H5 id="title-IDAVKCWC" class="docExampleTitle">Example 13-13. Referencing a variable set on a prior page in the session</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
&lt;?php
    session_start();
    echo $_SESSION['hello'];
?&gt;
</pre><br>

</TD></TR></table></p>
<p class="docText">Therefore, the code in <a class="docLink" href="#learnphpmysql-CHP-13-EX-13">Example 13-13</a> displays this information, as shown in <a class="docLink" href="#learnphpmysql-CHP-13-FIG-8">Figure 13-8</a>.</p>
<a name="learnphpmysql-CHP-13-FIG-8"></a><p><center>
<h5 class="docFigureTitle">Figure 13-8. The value set previously in the session is accessible</H5>
<img border="0" alt="" id="195131084204" width="500" height="170" SRC="images/learnphpmysql_1308.jpg">
</center></p><BR>
<p class="docText">Either <a class="docLink" href="#learnphpmysql-CHP-13-EX-11">Examples 13-11</a> or <a class="docLink" href="#learnphpmysql-CHP-13-EX-12">13-12</a> can be used to register the session variable before it's requested in <a class="docLink" href="#learnphpmysql-CHP-13-EX-13">Example 13-13</a>.</p>

<a name="learnphpmysql-CHP-13-SECT-3.2"></a>
<h4 id="title-IDAKMCWC" class="docSection2Title">13.3.2. Expanding Our Login Example</H4>
<p class="docText">Most login systems use session variables to pass useful information around without having to re-retrieve them from the database. In <a class="docLink" href="#learnphpmysql-CHP-13-EX-14">Example 13-14</a>, we're checking to see whether a user is valid, and then setting a few session variables.</P>
<a name="learnphpmysql-CHP-13-EX-14"></a><h5 id="title-IDAYMCWC" class="docExampleTitle">Example 13-14. Checking to see whether a user is valid</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;?php
session_start();
require_once('db_login.php');
require_once('DB.php');
if (empty($_SESSION['user_id'])) {
DELETE THIS PAR AFTER MOVING THE FIGURE ANCHOR ---&gt;
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "You must enter in a username and password combination!";
exit;
}
$connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database");
if (DB::isError($connection)){
die ("Could not connect to the database: &lt;br /&gt;". DB::errorMessage($connection));
}
$username = mysql_real_escape_string($_SERVER['PHP_AUTH_USER']);
$password = mysql_real_escape_string($_SERVER['PHP_AUTH_PW']);
$query = "SELECT `user_id`, `username` FROM `users` WHERE
`username`='".$username."' AND `password`=MD5('".$password."') LIMIT 1";
$result = $connection-&gt;query($query);
if(!($row = $result-&gt;fetchRow(DB_FETCHMODE_ASSOC))) {
header('WWW-Authenticate: Basic realm="Member Area"');
header("HTTP/1.0 401 Unauthorized");
echo "Your username and password combination was incorrect!";
exit;
}
$_SESSION['user_id'] = $row['user_id'];
$_SESSION['username'] = $row['username'];
}
echo "You have successfully logged in as ".$_SESSION["username"].".";
?&gt;
</pre><br>

</td></tr></table></p>
<p class="docText"><a class="docLink" href="#learnphpmysql-CHP-13-EX-14">Example 13-14</a> displays <a class="docLink" href="#learnphpmysql-CHP-13-FIG-9">Figure 13-9</a>, followed by <a class="docLink" href="#learnphpmysql-CHP-13-FIG-10">Figure 13-10</a>, if you were successful.</p>
<a name="learnphpmysql-CHP-13-FIG-9"></a><p><center>
<h5 class="docFigureTitle">Figure 13-9. The login prompt before entering our credentials</h5>
<img border="0" alt="" id="195131084204" width="405" height="214" SRC="images/learnphpmysql_1309.jpg">
</center></p><BR>
<a name="learnphpmysql-CHP-13-FIG-10"></a><p><center>
<h5 class="docFigureTitle">Figure 13-10. A successful login</H5>
<img border="0" alt="" id="195131084204" width="527" height="163" SRC="images/learnphpmysql_1310.jpg">
</center></P><br>
<p class="docText">The code first checks the session to see if the <tt>user_id</tt> session variable already has a value assigned to it. Subsequent pages can check for the session variables that were set at the end of <a class="docLink" href="#learnphpmysql-CHP-13-EX-14">Example 13-14</a> instead of doing another HTTP realm-based authentication and verifying that against the database.</P>
<p class="docText">If the session has the key <tt>user_id</tt>, you know the variable was set and you can continue without any further checking. However, email addresses and URLs are difficult to validate with 100% accuracy. Obviously, you'd mandate that an email address have an @ that is followed by some combination of letters, numbers, and the period. Lastly, there is a period followed by a two- to four-letter stringfor example, <tt>.nl, ca, com, edu, uk</tt>, or <tt>info</tt>. If you mandate certain parameters, you'll be more successful during validation.</p>
<p class="docText">When you're trying to validate a URL, you should check for the optional <a class="docLink" target="_blank" href="http://">http://</a>. After this, you want to see letters, numbers, or a dash, followed by a period, and then a two- to four-letter string as just described for email addresses.</p>

<a name="learnphpmysql-CHP-13-SECT-3.3"></a>
<h4 id="title-IDAFPCWC" class="docSection2Title">13.3.3. Ending a Session</H4>
<a name="IDX-CHP-13-0623"></a> 

<p class="docText">There are times when you want to end a session before the session times out. An example of this is when you provide a logout button or link on your page. The logout is actually done by ending<a name="IDX-CHP-13-0624"></a> 
 the user's session. To end a session, use the <tt>session_destroy</tt> function. Of course, you must first start a session for it to make sense to destroy it.</p>
<p class="docText">Keep in mind that ending a session doesn't make the values from that session unavailable to the rest of the currently executing PHP page. <a class="docLink" href="#learnphpmysql-CHP-13-EX-15">Example 13-15</a> provides a simple script that both ends the session and makes the session values unavailable to the rest of the PHP script.</P>
<a name="learnphpmysql-CHP-13-EX-15"></a><h5 id="title-IDAEQCWC" class="docExampleTitle">Example 13-15. Destroying a session</h5><P><table cellspacing="0" width="90%" border="1" cellpadding="5"><TR><td>

<pre>
&lt;?php
session_start();
// Do some miscellaneous work
$_SESSION['username'] = 'Michele';
// Logout of the site
session_destroy();
echo "At this point we can still see the value of username as
".$_SESSION['username']."&lt;br /&gt;";
$_SESSION = array();
echo "Now the value of username is blank: ".$_SESSION['username'];
?&gt;
</pre><BR>

</td></tr></table></P>
<p class="docText">The code in <a class="docLink" href="#learnphpmysql-CHP-13-EX-15">Example 13-15</a> produces something like <a class="docLink" href="#learnphpmysql-CHP-13-FIG-11">Figure 13-11</a>.</P>
<a name="learnphpmysql-CHP-13-FIG-11"></a><p><center>
<h5 class="docFigureTitle">Figure 13-11. Destroying a session and clearing out the values</h5>
<img border="0" alt="" id="195131084204" width="522" height="155" SRC="images/learnphpmysql_1311.jpg">
</center></p><BR>
<p class="docText">When you destroy the session, the session data is deleted from the server's session files. To wipe out the values in the <tt>$_SESSION</tt> global variable, set it to an empty array.</p>
<p class="docText">Although you're using <tt>$_SESSION</tt> to destroy the values from the session, if you used <tt>session_register</tt> to add variables to a session, you need to use one of two functions to remove the values from the running script. The function <tt>session_unset</tt> removes all session variables while <tt>session_unregister</tt> removes only the variable name that's sent as a parameter.</P>
<p class="docText">We're going to address garbage collection<a name="IDX-CHP-13-0625"></a> 
and no, this isn't about when your garbage is collected at the curb, this is when a session is destroyed or times out.</p>
<a name="learnphpmysql-CHP-13-SECT-3.3.1"></a>
<h5 id="title-IDA4RCWC" class="docSection3Title">13.3.3.1. Garbage collection</H5>
<a name="IDX-CHP-13-0626"></a> 

<p class="docText"><span class="docEmphasis">Garbage collection</span> determines what happens to the contents of a session on the server after a session is destroyed or simply times out from inactivity. If the server didn't do periodic clean up of old sessions, they'd accumulate, endlessly wasting space, and creating clutter on the server. Garbage collection happens automatically and deletes all old session data.</P>
<p class="docText">PHP has a load-balancing feature for garbage collection, so that old session files aren't deleted for every session request. The default timeout for session files is 1440 seconds or 24 minutes. That probably doesn't seem like a lot of time if you have a very robust site, but PHP has commands that can delete garbage following parameters you set. A session file can be deleted after that timeout, but it could reside on the server longer, depending on the amount of sessions created.</p>
<p class="docText">The following PHP <span class="docEmphasis">.ini</span> variables deal with the garbage collector:</P>
<ul><li><p class="docList"><tt>session.gc_maxlifetime</tt></p></li><li><p class="docList"><tt>session.gc_probability</tt></p></li><li><p class="docList"><tt>session.gc_divisor</tt></p></li></ul>
<p class="docText">In the above variables, <tt>gc</tt> equals garbage collector. If you have enough disk space on your server, you can set the session file timeout pretty long in order to preserve most or even all sessions until the browsers are closed. However, in many cases, the session needs to expire after a certain time, so you have to change the lifetime of the session cookie itself.</p>
<p class="docText">We'll discuss setting the session's timeout<a name="IDX-CHP-13-0627"></a> 
 values so you get a better understanding of what you're going to need to do.</P>

<a name="learnphpmysql-CHP-13-SECT-3.3.2"></a>
<h5 id="title-IDARTCWC" class="docSection3Title">13.3.3.2. Setting a session's timeout</h5>
<a name="IDX-CHP-13-0628"></a> 
<a name="IDX-CHP-13-0629"></a> 

<p class="docText">After a certain time period, it's reasonable to expect that a user's session should automatically log out, which is essentially an expiration period. PHP allows you to specifically set this duration. The best way to do this is to modify the <span class="docEmphasis">.htaccess</span> file.</P>
<p class="docText">The <span class="docEmphasis">.htaccess</span> file affects the HTML and PHP files in the same directory as the file. It allows you to make configuration changes without modifying Apache's configuration files. Any changes made in the <span class="docEmphasis">.htaccess</span> file also apply to files in subdirectories unless another <span class="docEmphasis">.htaccess</span> file is in a subdirectory. In <a class="docLink" href="#learnphpmysql-CHP-13-EX-16">Example 13-16</a>, we're using the <tt>session.gc_maxlifetime</tt> variable.</P>
<a name="learnphpmysql-CHP-13-EX-16"></a><h5 id="title-IDAUUCWC" class="docExampleTitle">Example 13-16. Session timeout</H5><p><table cellspacing="0" width="90%" border="1" cellpadding="5"><tr><td>

<pre>
&lt;IfModule mod_php4.c&gt;
  php_value session.gc_maxlifetime "14400"
&lt;/IfModule&gt;
</pre><BR>

</td></TR></table></p>
<p class="docText">The value that comes after <tt>sessions.gc_maxlifetime</tt> is in 100ths of a second, so, if you want a session timeout of 30 minutes, you would use a value of 18000.</p>
<P><table border="0" bgcolor="black" cellspacing="0" cellpadding="1" width="90%" align="center"><TR><td><table bgcolor="white" width="100%" border="0" cellspacing="0" cellpadding="6"><TR><td width="60" valign="top"><img src="images/tip_yellow.jpg" width="50" height="54" alt=""></td><TD valign="top">
<p class="docText">The cookie path can be <span class="docEmphasis">/</span> or <span class="docEmphasis">/directoryx</span> if the cookie needs to be valid for a certain directory only. <span class="docEmphasis">directoryx</span> could be any directory or folder you have named specifically for the cookies.</P>
<p class="docText">As seen in <a class="docLink" href="#learnphpmysql-CHP-13-EX-16">Example 13-16</a>, we have a session cookie with a custom-defined lifetime and a defined garbage collector timeout. This ensures that the current session data is available as long as the session cookie in the browser is valid. Authentication with <tt>Auth_HTTP</tt><a name="IDX-CHP-13-0630"></a> 
 is going to be discussed.</p>
</td></tr></table></td></TR></table></p><BR>



</TD></TR></table>
<br>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-13-SECT-2.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=learnphpmysql-CHP-13-SECT-4.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
<script type="text/javascript"><!--
google_ad_client = "pub-0203281046321155";
google_alternate_ad_url = "http://www.bookhtml.com/adbrite.htm";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel ="4867465545";
google_color_border = "FFFFFF";
google_color_link = "0000FF";
google_color_bg = "FFFFFF";
google_color_text = "000000";
google_color_url = "0000FF";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</html>
